home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / mnp_c.zip / MNPDRVR.C < prev    next >
C/C++ Source or Header  |  1990-05-16  |  22KB  |  889 lines

  1. /*=====================================================================
  2.  
  3.                       The Microcom MNP Library
  4.                         (Microsoft C Version)
  5.  
  6.     10/05/89 - lcb.lt_rsn++ fix in rcv_lt...gp
  7.     11/4/87 - explicit data typing...gp
  8.     8/27/87 - rcv_lt() modified to use lcb.lcl_credit..gp
  9.  
  10. -----------------------------------------------------------------------
  11.  
  12.         LDRIVER - MNP Link RS-232 Interrupt Service Routines
  13.  
  14.      This module implements asynchronous I/O for IBM PC-compatible
  15.      machines and thus much of this code may not be portable to 
  16.      other dissimilar environments.
  17.  
  18.      This code implements Class 2 of the MNP link protocol,
  19.      i.e. it uses the stop/start byte-oriented framing technique.
  20.      A Class 3 implementation is not possible in the IBM PC 
  21.      environment since the communications hardware is not capable
  22.      of switching to synchronous (bit-oriented) operation.
  23.      Protocol messages and procedures, however, are independent
  24.      of the framing technique.        
  25.  
  26.      Global routines:
  27.  
  28.     - ascode: service I/O interrupt 
  29.     - lne_stat: check carrier status 
  30.     - trigger_sf: initiate transmit interrupts
  31.  
  32. =====================================================================*/
  33.  
  34. /* Header files
  35. */
  36. #include <dos.h>
  37. #include <mnpdat.h>
  38.  
  39. /* Interrupt-related definitions
  40. */
  41. #define INT_8259A_PORT    0x20
  42. #define EOI        0x20
  43. #define RCV_DATA    4
  44. #define THR_EMPTY    2
  45. #define MODSTAT_CHNG    0
  46.  
  47. /* Send framer state names
  48. */
  49. #define SF_INIT     0
  50. #define SF_DLE        1
  51. #define SF_STX        2
  52. #define SF_INFO     3
  53. #define SF_DLEINFO    4
  54. #define SF_ETX        5
  55. #define SF_FCS1     6
  56. #define SF_FCS2     7
  57.  
  58. /* Receive framer state names
  59. */
  60. #define RF_INIT     0
  61. #define RF_DLE        1
  62. #define RF_STX        2
  63. #define RF_HDLEN    3
  64. #define RF_HEADER    4
  65. #define RF_INFOL    5
  66. #define RF_INFO     6
  67. #define RF_FCS1     7
  68. #define RF_FCS2     8
  69.  
  70. /* Frame octet definitions
  71. */
  72. #define SYN        0x16
  73. #define DLE        0x10
  74. #define ETX        3
  75. #define STX        2
  76.  
  77. /* Length of header buffer (maximum acceptable LPDU header)
  78. */
  79. #define MAX_HDRLEN    100
  80.  
  81. /* Bit set, clear and test definitions
  82. */
  83. #define SETBIT1(bit)    lcb.status_1 |= bit;       
  84. #define SETBIT2(bit)    lcb.status_2 |= bit;
  85. #define SETBIT3(bit)    lcb.status_3 |= bit;
  86. #define CLRBIT1(bit)    lcb.status_1 &= ~bit;         
  87. #define CLRBIT2(bit)    lcb.status_2 &= ~bit;
  88. #define CLRBIT3(bit)    lcb.status_3 &= ~bit;
  89. #define BIT1SET(bit)    (lcb.status_1 & bit)         
  90. #define BIT2SET(bit)    (lcb.status_2 & bit)
  91. #define BIT3SET(bit)    (lcb.status_3 & bit)
  92.  
  93. /* External references
  94. */
  95. extern USIGN_16 iir_add;            /* int id reg address */
  96. extern USIGN_8 linestat;            /* line status var */
  97. extern struct TIMERS tmr;
  98. extern struct link_ctl_blk lcb;  /* link control block */
  99. extern struct BUFFER rb, ftb, rlkb;  /* buffers */
  100. extern USIGN_8 *rb_iptr;        /* rcv buf insert pointer */
  101. extern USIGN_16 rb_cnt,tbcnt;        /* buffer counts */
  102. extern USIGN_8 rbuf[RBUF_LEN];    /* receive buffer */
  103.  
  104. /* Function definitions
  105. */
  106. void snd_framer();
  107. void rcv_framer();
  108. void mod_stat();
  109. void rcv_lt();
  110. void rcv_la();
  111. void rcv_lna();
  112. void rcv_ln();
  113.  
  114. /* Local data
  115. */
  116. USIGN_8 *sf_ptr,
  117.      *rf_hptr,
  118.      *rf_dptr;
  119. USIGN_8 snd_char,
  120.      rcv_char;
  121. struct 
  122.     {
  123.     USIGN_8 low;
  124.     USIGN_8 hi;
  125.     }
  126.         snd_fcs,            /* send fcs */
  127.           rcv_fcs,            /* calculated receive fcs */
  128.           rfcs;            /* received fcs */
  129. USIGN_16 rdle_flg;            /* 'previous char DLE' flag */
  130. USIGN_16 rf_hdrlen,            /* receive header length  */
  131.     hdrcnt,            
  132.     rf_datlen,
  133.     sf_state,                /* send framer state var */
  134.     rf_state,                /* receive framer state var */
  135.     sf_len,
  136.     sf_busy,                /* 'send frame' flag */
  137.     sf_lt,                /* 'sending LT' flag */
  138.     frame_snt,                /* 'info field sent' flag */ 
  139.     frame_rcvd,            /* 'frame received' flag */
  140.     frame_dne;                /* 'frame sent' flag */
  141. USIGN_8 *rf_tiptr;
  142.  
  143. struct MNP_CB *p_mnpcb;
  144. struct BLST *dat_struct, *hdr_struct;
  145.  
  146. USIGN_16 modem_out_busy;    /* RS-232 hardware status flag
  147.                               0=transmitter not active
  148.                               1=transmitter active */
  149.  
  150. /* Function declarations
  151. */
  152. USIGN_8 get_char();
  153.  
  154. /*GLOBAL***************************************************************
  155.  
  156.     ascode - MNP RS-232 interrupt service routine
  157.  
  158.      This routine is called by 'async' (in module 'async.asm')
  159.      to service an async I/O interrupt.
  160.  
  161. **********************************************************************/
  162.  
  163. ascode()
  164. {
  165.  
  166. USIGN_8 int_id_reg;            /* value in int id reg */
  167.  
  168. /* Handle interrupts for as long as there are any. 
  169. */
  170. for (;;)
  171.     {
  172.  
  173. /* Read the Interrupt Identification Register.  If bit 0 is on, 
  174. ** there is no interrupt.  In this case cancel the interrupt by writing ** the "end-of-interrupt" byte to the Oper Ctl Word 2 and return. 
  175. */
  176.     if ((int_id_reg = inp(iir_add)) & BIT0_ON)
  177.         {
  178.         outp(INT_8259A_PORT, EOI);
  179.         return;
  180.         }
  181.  
  182. /* Since bit 0 is off, there is an interrupt.  Take action based
  183. ** on the type of interrupt. 
  184. */
  185.     switch (int_id_reg)
  186.         {
  187.  
  188. /* Receive buffer full interrupt
  189. */
  190.         case RCV_DATA:                
  191.             rcv_framer();
  192.             if ((sf_busy == FALSE)
  193.                 || ((inp(iir_add + 3) & 0x20) == 0))
  194.                 break;
  195.  
  196. /* Transmit buffer empty interrupt
  197. */
  198.         case THR_EMPTY:
  199.             snd_framer();
  200.             break;
  201.  
  202. /* Modem status change interrupt
  203. */
  204.         case MODSTAT_CHNG:            
  205.             mod_stat();
  206.             break;
  207.         }
  208.     }
  209. }
  210.  
  211. /*GLOBAL***************************************************************
  212.  
  213.     lne_stat - physical-connection status routine
  214.  
  215. **********************************************************************/
  216.  
  217. SIGN_16 lne_stat()
  218. {
  219.  
  220. /* If the carrier detect bit is 1, return success (physical-connection
  221. ** still active).  Otherwise, return with a failure indication. 
  222. */
  223. if (linestat & 0x80)
  224.     return (SUCCESS);
  225. else
  226.     return (1);
  227. }
  228.  
  229. /*GLOBAL***************************************************************
  230.  
  231.     trigger_sf - initiate send framer
  232.  
  233. **********************************************************************/
  234.  
  235. void trigger_sf()
  236. {
  237.  
  238. extern USIGN_16 port_add;
  239.  
  240. /* If the RS-232 transmitter is not already busy, then a byte must 
  241. ** be placed in the transmit buffer to begin interrupt-driven sending.
  242. ** This is the start of a frame and thus the first byte to be sent is
  243. ** the SYN which begins the frame start flag.  Also the send framer's
  244. ** state variable is initialed here.
  245. */ 
  246. if (!modem_out_busy)
  247.     {
  248.     modem_out_busy = TRUE;
  249.     sf_state = SF_DLE;                
  250.     outp(port_add,SYN);
  251.     }
  252. }
  253.  
  254. /*LOCAL----------------------------------------------------------------
  255.  
  256.     get_char - get byte from send buffer
  257.  
  258. ---------------------------------------------------------------------*/
  259.  
  260. USIGN_8 get_char()
  261. {
  262.  
  263. /* Return the byte at the current send framer pointer position.
  264. ** In the process, advance the point for next time and reduce the
  265. ** number of bytes remaining by one.
  266. */
  267. sf_len--;                    
  268. return (*sf_ptr++);
  269. }
  270.  
  271. /*LOCAL----------------------------------------------------------------
  272.  
  273.     mod_stat - modem status change interrupt service routine
  274.  
  275. ---------------------------------------------------------------------*/
  276.  
  277. void mod_stat()
  278. {
  279.  
  280. /* Read modem status register and save the value.
  281. */
  282. linestat = inp(iir_add + 4);
  283.  
  284. /* If carrier has been lost, signal the mainline that the link
  285. ** also has been lost by lowering the 'link established' flag. 
  286. */
  287. if (!(linestat & 0x80))
  288.     CLRBIT1(LINK_EST)    
  289.  
  290. }
  291.  
  292. /*LOCAL----------------------------------------------------------------
  293.  
  294.     put_char - store an LT data byte
  295.  
  296. ---------------------------------------------------------------------*/
  297.  
  298. void put_char()
  299. {
  300.  
  301. /* Ignore this byte if the amount of received data exceeds the
  302. ** negotiated maximum user data size for the LT LPDU.  This could occur
  303. ** if the frame is broken or if the correspondent is misbehaving. 
  304. */
  305. if (rf_datlen >= lcb.max_data_sz)
  306.     return;
  307.  
  308. /* Otherwise, accept this byte. 
  309. */
  310. rf_datlen++;                
  311. fcscalc (&rcv_fcs, rcv_char);
  312.  
  313. /* Now store the data byte in the receive buffer using the temporary
  314. ** insert pointer.  Advance the pointer, checking for wrap.
  315. */
  316. *rf_tiptr++ = rcv_char;            
  317. if (rf_tiptr >= rbuf + RBUF_LEN)
  318.     rf_tiptr = rbuf;
  319.  
  320. }
  321.  
  322. /*LOCAL----------------------------------------------------------------
  323.  
  324.     put_hdr - store an LPDU header byte
  325.  
  326. ---------------------------------------------------------------------*/
  327.  
  328. void put_hdr()
  329. {
  330.  
  331. /* Store header byte in header buffer.  Increment count of bytes in
  332. ** the buffer and include the byte in the receive fcs.
  333. */
  334. rf_hdrlen++;
  335. *rf_hptr++ = rcv_char;                  
  336. fcscalc (&rcv_fcs, rcv_char);
  337.  
  338. }
  339.  
  340. /*LOCAL----------------------------------------------------------------
  341.  
  342.     RCV_FRAMER - Receive Framer
  343.  
  344. ---------------------------------------------------------------------*/
  345.  
  346. void rcv_framer()
  347. {
  348.  
  349. extern USIGN_16 port_add;
  350.  
  351. /* Get received data byte and save it for later
  352. */
  353. rcv_char = inp(port_add);
  354.  
  355. /* Take action based on current state of receive finite state machine.
  356. ** 'rf_state' is the state variable.
  357. */
  358. switch (rf_state)
  359.     {
  360.  
  361. /* State RF_INIT - This is the initial state.  Search the received
  362. ** data stream for a SYN character which may be the beginning
  363. ** of the start flag sequence of a byte mode frame. 
  364. */
  365.     case RF_INIT:
  366.         if (rcv_char == SYN)
  367.             rf_state++;    
  368.         break;
  369.  
  370. /* State RF_DLE - Search for the second byte in the start flag, a DLE
  371. ** byte.  Go back to the initial state (SYN search) if this byte is
  372. ** something other than a DLE.
  373. */
  374.     case RF_DLE:
  375.         if (rcv_char == DLE)
  376.              rf_state++; 
  377.         else 
  378.             rf_state--;        
  379.         break;
  380.  
  381. /* State RF_STX - If the received byte is an STX then a frame start flag
  382. ** has been found.    In this case, initialize to receive an LPDU.
  383. ** Otherwise, go back to looking for a SYN. 
  384. */
  385.     case RF_STX:
  386.         if (rcv_char == STX)
  387.             {
  388.             get_b(&rlkb,&hdr_struct);
  389.             rf_hptr = hdr_struct->bptr;
  390.             hdrcnt=rf_hdrlen=rf_datlen=rdle_flg=0;
  391.             rcv_fcs.hi=rcv_fcs.low=NULL;
  392.                 rf_state++;         
  393.                 }
  394.         else                
  395.                 rf_state = RF_INIT;         
  396.         break;
  397.  
  398. /* State RF_HDLEN - Get the first byte of the LPDU, the length
  399. ** indicator.  Wait for the next byte if this happens to be a DLE (in a
  400. ** good frame the DLE will be doubled).  If the value  received is
  401. ** greater than this implementation's maximum header length, it must be
  402. ** a protocol error or the value is broken.  In either case, ignore this
  403. ** LPDU. This is like a broken frame, so force the sender to ack. 
  404. */
  405.     case RF_HDLEN:
  406.         if ((rcv_char != DLE) || ((rcv_char == DLE) && rdle_flg))
  407.             {
  408.             rdle_flg = 0;        
  409.         
  410.             if (rcv_char > MAX_HDRLEN)
  411.                 {
  412.                 ret_b(&rlkb, hdr_struct);    
  413.                 SETBIT2(FORCE_ACK)
  414.                 rf_state = RF_INIT;        
  415.                 }
  416.                 else
  417.                 {
  418.                 hdrcnt = rcv_char;
  419.                 put_hdr();
  420.                 rf_state++;
  421.                 }
  422.                 }
  423.         else
  424.                 rdle_flg = TRUE;
  425.         break;
  426.  
  427. /* State RF_HEADER - Receive header bytes, assuming the length indicator
  428. ** was correct.  Any bytes following the header will temporarily be
  429. ** assumed to be data.
  430. */
  431.     case RF_HEADER:
  432.         if ((rcv_char != DLE) || ((rcv_char == DLE) && rdle_flg)) 
  433.             {
  434.                 rdle_flg = FALSE;
  435.                 put_hdr();
  436.                 if (!(--hdrcnt))
  437.                 rf_state++;
  438.                 }
  439.         else
  440.                 rdle_flg = TRUE;
  441.         break;
  442.  
  443. /* State RF_INFOL -  Receive first data byte.  Note that we must check
  444. ** for the stop flag just in case the length indicator byte was broken.  ** When the first data byte is received, the temporary insert pointer
  445. ** into the data receive buffer is initialized to the current location
  446. ** of the real pointer.
  447. */
  448.     case RF_INFOL:
  449.         if ((rcv_char != DLE) || ((rcv_char == DLE) && rdle_flg))
  450.             {
  451.                 if ((rcv_char == ETX) && rdle_flg) 
  452.                 {
  453.                 fcscalc(&rcv_fcs, rcv_char);
  454.                 rf_state = RF_FCS1;
  455.                 }
  456.                 else
  457.                 {
  458.                 rdle_flg = FALSE;
  459.                     rf_tiptr = rb_iptr;         
  460.                     put_char();
  461.                 rf_state++;            
  462.                 }
  463.             }
  464.         else
  465.                 rdle_flg = TRUE;
  466.         break;
  467.  
  468. /* State RF_INFO - Receive data bytes until the stop flag is found.
  469. */
  470.     case RF_INFO:
  471.         if ((rcv_char != DLE) || ((rcv_char == DLE) && rdle_flg))
  472.             {
  473.                 if ((rcv_char == ETX) && rdle_flg)
  474.                 {
  475.                 fcscalc(&rcv_fcs, rcv_char);
  476.                 rf_state++;        
  477.                 }
  478.                 else
  479.                 put_char();
  480.                 rdle_flg = FALSE;
  481.                 }
  482.         else
  483.                 rdle_flg = TRUE;
  484.         break;
  485.  
  486. /* State RF_FCS1 - Receive first byte of fcs.
  487. */
  488.     case RF_FCS1:
  489.         rfcs.hi = rcv_char;
  490.         rf_state++;
  491.         break;
  492.  
  493. /* State RF_FCS2 - Receive second (low) byte of fcs and take end-of-
  494. ** frame action.  If the calculated fcs is not identical to that
  495. ** received, the received frame is "broken".  Signal this to the sender
  496. ** by setting the LPDU type to 0 and setting the FORCE_ACK flag.  If the
  497. ** FCS's match, take action based on the type of LPDU received. 
  498. */
  499.     case RF_FCS2:
  500.         if ((rcv_fcs.hi != rfcs.hi) || (rcv_fcs.low != rcv_char))
  501.             {
  502.                 lcb.lpdu_type = 0;
  503.                 SETBIT2(FORCE_ACK);
  504.                 ret_b(&rlkb, hdr_struct);
  505.                 }
  506.         else
  507.             {
  508.                 switch (lcb.lpdu_type = *(hdr_struct->bptr + PDU_TYPE))
  509.                 {
  510.                 case LT:
  511.                         rcv_lt();
  512.                         break;
  513.  
  514.                 case LA:
  515.                         rcv_la();
  516.                         break;
  517.  
  518. /* Link Request - If an LR arrives during what we think is the data
  519. ** phase, the other side may be retransmitting. In this case, just
  520. ** discard the LR.  Otherwise, save the LR for the mainline to process.
  521. ** In either case, signal the mainline to ack. 
  522. */
  523.                 case LR:
  524.                         if (BIT1SET(LINK_EST))
  525.                         ret_b(&rlkb, hdr_struct);
  526.                         else
  527.                         rlkb.used_lst = hdr_struct;  
  528.                         SETBIT2(FORCE_ACK)
  529.                         break;
  530.  
  531.                 case LN:
  532.                         rcv_ln();
  533.                         break;
  534.  
  535.                 case LNA:
  536.                         rcv_lna();
  537.                         break;
  538.  
  539. /* Link Disconnect - Signal link termination to the mainline.  If the LD
  540. ** contains a user reason byte (signalled by parm 1 having a value of
  541. ** 255), save it in the LCB. 
  542. */
  543.                 case LD:
  544.                         CLRBIT1(LINK_EST)
  545.                         if (*(hdr_struct->bptr + 4) == 255)
  546.                         {
  547.                         p_mnpcb->ld_source = 1;
  548.                         p_mnpcb->ld_reason = 
  549.                             *(hdr_struct->bptr+7);
  550.                         }
  551.                         else
  552.                         p_mnpcb->ld_source = 0;
  553.                         break;
  554.                 }
  555.                 }
  556.  
  557. /* Signal the mainline that a frame has been received and reset the
  558. ** receive frame state machine for the next frame. 
  559. */
  560.                 frame_rcvd = TRUE;            
  561.                 rf_state = RF_INIT;     
  562.                 break;
  563.         }
  564.  
  565. }
  566.  
  567. /*LOCAL----------------------------------------------------------------
  568.  
  569.     rcv_la - process a received LA LPDU
  570.  
  571. ---------------------------------------------------------------------*/
  572.  
  573. void rcv_la()
  574. {
  575.  
  576. register USIGN_8 *p;
  577. USIGN_16 i;
  578. USIGN_8 lt_ret_seq;
  579.  
  580. /* Ignore this LA LPDU if a destructive attention is in progress. 
  581. */
  582. if (BIT3SET(LN_SENT))
  583.     {
  584.     ret_b(&rlkb,hdr_struct);
  585.         return;
  586.         }
  587.  
  588. /* For reasons of robustness, check the validity of the LA LPDU 
  589. */
  590. p = hdr_struct->bptr + 2;            /* point to parm 1 */
  591. if ((*p++ != 1) || (*p != 1))
  592.     {
  593.     ret_b(&rlkb,hdr_struct);
  594.     return;
  595.     }
  596. p += 2;
  597. if ((*p++ != 2) || (*p != 1))
  598.     {
  599.     ret_b(&rlkb,hdr_struct);
  600.     return;
  601.     }
  602.  
  603. /* If the receive sequence number of this LA is the same as the last
  604. ** one received, it may be an implied negative acknowledgment.  Force
  605. ** the mainline to consider retransmission by setting the 'force
  606. ** retransmission' flag.  Otherwise, save the new number as the last
  607. ** acked and set the 'good ack received' flag. 
  608. */
  609. p -= 2;
  610. if (*p == lcb.ltssn_acked)
  611.     SETBIT2(FORCE_RET)
  612. else
  613.     {
  614.     lcb.ltssn_acked = *p;
  615.         SETBIT1(LA_RECEIVED)
  616.         }
  617.  
  618. /* Process the new credit information received. If it is zero, return.
  619. */
  620. p += 3;
  621. if ((lcb.rem_credit = *p) == 0)
  622.     {
  623.     ret_b(&rlkb,hdr_struct);
  624.         return;
  625.         }
  626.  
  627. /* If credit is not zero and this ack was a good one, take into account
  628. ** the LT LPDUs that may have been sent since the correspondent sent
  629. ** this LA.  That is, subtract from the credit the number of these not
  630. ** yet acked LTs. 
  631. */
  632. if (BIT1SET(LA_RECEIVED) && tbcnt)
  633.     {
  634.     lt_ret_seq = *(ftb.used_lst->bptr + LT_SEQ);
  635.  
  636.     if (lt_ret_seq <= lcb.ltssn_acked)
  637.         i = (lcb.ltssn_acked - lt_ret_seq) + 1;
  638.     else
  639.         i = (256 - lt_ret_seq) + lcb.ltssn_acked + 1;
  640.  
  641.         i = tbcnt - i;
  642.         if (lcb.rem_credit >= i)
  643.         {
  644.         lcb.rem_credit -= i;
  645.             if (lcb.rem_credit < 0)
  646.             lcb.rem_credit = 0;
  647.             }
  648.         else
  649.         lcb.rem_credit = 0;
  650.         }
  651.  
  652. /* Clean up 
  653. */
  654. ret_b(&rlkb, hdr_struct);
  655.  
  656. }
  657.  
  658. /*LOCAL----------------------------------------------------------------
  659.  
  660.     rcv_ln - process a received LN LPDU
  661.  
  662. ---------------------------------------------------------------------*/
  663.  
  664. void rcv_ln()
  665. {
  666.  
  667. register USIGN_8 *p;
  668.  
  669. /* Check the sequence number of this LN LPDU.  If it is the next one
  670. ** in the sequence space, signal its arrival to the sender by
  671. ** setting the LN_RECEIVED flag.  Also remember the type of the LN LPDU
  672. ** by saving the type parameter value in the LCB. 
  673. */
  674. p = hdr_struct->bptr + 4;
  675. if (*p == (USIGN_8) ++lcb.ln_rsn)
  676.     {
  677.     lcb.ln_rtype = *(p + 3);
  678.         SETBIT3(LN_RECEIVED)
  679.         }
  680.  
  681. /* If this is not the next one, then decrement the receive sequence
  682. ** number which was incremented above and signal the need to send an
  683. ** LNA LPDU.
  684. */
  685. else
  686.     {
  687.     lcb.ln_rsn--;
  688.     SETBIT3(FORCE_LNA)
  689.     }
  690.  
  691. ret_b(&rlkb, hdr_struct);
  692. }
  693.  
  694. /*LOCAL----------------------------------------------------------------
  695.  
  696.     rcv_lna -  process a received LNA LPDU
  697.  
  698. ---------------------------------------------------------------------*/
  699.  
  700. void rcv_lna()
  701. {
  702.  
  703. register USIGN_8 *p;
  704.  
  705. /* If the LNA LPDU is an acknowledgment of an outstanding LN, its
  706. ** sequence number will match that of the last LN sent.    In this
  707. ** case, signal the sender that the LN has been acknowledged.  
  708. ** Otherwise, just ignore this LPDU. 
  709. */
  710. if (*(hdr_struct->bptr + 4) == lcb.ln_ssn)
  711.     {
  712.     lcb.ln_ret_cnt = NULL;
  713.     CLRBIT3(LN_SENT)
  714.     CLRBIT3(LN_TIMER)
  715.     tmr.ln = NULL;    
  716.     }
  717. ret_b(&rlkb, hdr_struct);
  718. }
  719.  
  720. /*LOCAL----------------------------------------------------------------
  721.  
  722.     rcv_lt - process a received LT LPDU
  723.  
  724. ---------------------------------------------------------------------*/
  725.  
  726. void rcv_lt()
  727. {
  728.  
  729. /* Ignore this LT LPDU if a destructive attention is in progress. 
  730. */
  731. if (BIT3SET(LN_SENT))
  732.     {
  733.     ret_b(&rlkb, hdr_struct);
  734.         return;
  735.         }
  736.  
  737. /* Reset window timer, if window timer is enabled. 
  738. */
  739. if (BIT2SET(WNDW_TIMER))
  740.     tmr.fcw = lcb.window_tmr;
  741.  
  742. /* Accept this LT LPDU if it is the next one in the sequence space
  743. ** and there is room for it (i.e. there is a receive credit).
  744. */
  745. if ((lcb.lcl_credit > 0)
  746.      && (USIGN_8)(*(hdr_struct->bptr + LT_SEQ) == (USIGN_8) (lcb.lt_rsn+1)))
  747.     { 
  748.     lcb.lt_rsn++;
  749.     --lcb.lcl_credit;
  750.     CLRBIT3(DUP_IGNORED)
  751.         rb_iptr = rf_tiptr;    
  752.         rb_cnt = rb_cnt + rf_datlen;
  753.         }
  754.  
  755. /* Otherwise, ignore the LT LPDU. In this case, set the FORCE_ACK flag
  756. ** to get the sender to ack as rapidly as possible.
  757. */
  758. else
  759.     {
  760.         SETBIT2(FORCE_ACK)
  761.  
  762. /* If the LT LPDU is the same as the last one which arrived, i.e. it is
  763. ** an immediate duplicate, and this is the first occurrence of the
  764. ** immediate duplicate, then don't force the sender to ack this time. 
  765. */
  766.     if ((*(hdr_struct->bptr + LT_SEQ) == lcb.lt_rsn)
  767.         && !BIT3SET(DUP_IGNORED))
  768.         {
  769.         CLRBIT2(FORCE_ACK)
  770.         SETBIT3(DUP_IGNORED)        
  771.         }
  772.         }
  773.  
  774. /* Clean up 
  775. */
  776. ret_b(&rlkb, hdr_struct);
  777. }
  778.  
  779. /*LOCAL----------------------------------------------------------------
  780.  
  781.     snd_framer - handle a transmit holding register empty
  782.                 interrupt.  This subroutine sends a byte-mode frame.
  783.  
  784. ---------------------------------------------------------------------*/
  785.  
  786. void snd_framer()
  787. {
  788.  
  789. extern USIGN_16 port_add;
  790.  
  791. /* Take action based on the current state of the framer state machine. 
  792. */
  793. switch (sf_state)
  794.     {
  795.  
  796. /* State SF_INIT - initial state.  If the mainline has designated an
  797. ** LPDU to frame, the sf_busy flag will be true.  If this is the case,
  798. ** begin the start flag of the frame. 
  799. */
  800.     case SF_INIT:
  801.     if (sf_busy)
  802.         {
  803.         snd_char = SYN;
  804.         sf_state++;
  805.         break;
  806.         }
  807.     else
  808.         {
  809.         frame_dne = 1;
  810.         modem_out_busy = FALSE;
  811.         return;
  812.         }
  813.  
  814. /* State SF_DLE - Send DLE of start flag. 
  815. */
  816.     case SF_DLE:
  817.         snd_fcs.hi = snd_fcs.low = 0;
  818.         snd_char = DLE;
  819.         sf_state++;                
  820.         break;
  821.  
  822. /* State SF_STX - Send STX of start flag. 
  823. */
  824.     case SF_STX:
  825.         snd_char = STX;
  826.         sf_state++;
  827.         break;
  828.  
  829. /* State SF_INFO -  As long as there are info field bytes, send a 
  830. ** byte and double DLE's as necessary.  At the end of the information
  831. ** field of the frame, start the end flag.   Signal the mainline code
  832. ** that it can enqueue another frame if it is already waiting on
  833. ** 'frame_snt'.  Clearing 'sf_busy' will cause the framer to stop after
  834. ** the end flag unless another frame has been enqueued. 
  835. */
  836.     case SF_INFO:
  837.         if (sf_len > 0)
  838.             {
  839.             if ((snd_char = get_char()) == DLE)
  840.             sf_state++;
  841.             fcscalc(&snd_fcs, snd_char);
  842.             }
  843.         else
  844.             {
  845.             sf_busy = sf_lt = FALSE;
  846.             frame_snt = TRUE;
  847.             snd_char = DLE;
  848.             sf_state = SF_ETX;
  849.             }
  850.         break;
  851.  
  852. /* State SF_DLEINFO - Double an info field DLE.
  853. */
  854.     case SF_DLEINFO:
  855.         snd_char = DLE;
  856.         sf_state--;
  857.         break;
  858.  
  859. /* State SF_ETX - Send ETX of end flag.
  860. */
  861.     case SF_ETX:
  862.         snd_char = ETX;
  863.         fcscalc(&snd_fcs, snd_char);
  864.         sf_state++;
  865.         break;
  866.  
  867. /* State SF_FCS1 - Send first byte of frame check sequence.
  868. */
  869.     case SF_FCS1:
  870.         snd_char = snd_fcs.hi;
  871.         sf_state++;
  872.         break;
  873.  
  874. /* State SF_FCS2 - Send second byte of frame check sequence.
  875. ** After this byte is sent, the send framer goes back to its
  876. ** initial state.
  877. */
  878.     case SF_FCS2:
  879.         snd_char = snd_fcs.low;
  880.         sf_state = SF_INIT;
  881.         break;
  882.     }
  883.  
  884. /* Send byte out RS-232 port 
  885. */
  886. outp(port_add, snd_char);
  887.  
  888. }
  889.